package com.evan.review.anr;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.evan.review.R;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * ANR 错误与正确案例对比Activity
 * 
 * 本Activity展示了导致ANR的常见错误操作和对应的正确实现方式
 * 通过在同一界面中对比展示，帮助理解如何正确避免ANR问题
 */
public class ANRComparisonActivity extends AppCompatActivity {

    private static final String TAG = "ANRComparisonActivity";
    
    // UI组件
    private Button btnWrongNetworkOp; // 错误的网络操作按钮
    private Button btnCorrectNetworkOp; // 正确的网络操作按钮
    
    private Button btnWrongFileOp; // 错误的文件操作按钮
    private Button btnCorrectFileOp; // 正确的文件操作按钮
    
    private Button btnWrongUIBlock; // 错误的UI阻塞操作按钮
    private Button btnCorrectUIBlock; // 正确的UI非阻塞操作按钮
    
    private Button btnWrongBroadcast; // 错误的广播接收器实现按钮
    private Button btnCorrectBroadcast; // 正确的广播接收器实现按钮
    
    private TextView tvLogger; // 日志文本框
    private ScrollView svLogger; // 日志滚动视图
    
    // 线程池，用于正确案例中的并发操作
    private final ExecutorService executorService = Executors.newCachedThreadPool();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anr_comparison);
        
        initViews(); // 初始化视图
        setListeners(); // 设置监听器
        
        logMessage("本界面展示了导致ANR的常见错误操作和对应的正确实现方式");
        logMessage("请点击按钮体验不同案例的对比效果");
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        executorService.shutdown(); // 关闭线程池
    }
    
    /**
     * 初始化视图组件
     */
    private void initViews() {
        btnWrongNetworkOp = findViewById(R.id.btn_wrong_network_op);
        btnCorrectNetworkOp = findViewById(R.id.btn_correct_network_op);
        
        btnWrongFileOp = findViewById(R.id.btn_wrong_file_op);
        btnCorrectFileOp = findViewById(R.id.btn_correct_file_op);
        
        btnWrongUIBlock = findViewById(R.id.btn_wrong_ui_block);
        btnCorrectUIBlock = findViewById(R.id.btn_correct_ui_block);
        
        btnWrongBroadcast = findViewById(R.id.btn_wrong_broadcast);
        btnCorrectBroadcast = findViewById(R.id.btn_correct_broadcast);
        
        tvLogger = findViewById(R.id.tv_logger);
        svLogger = findViewById(R.id.sv_logger);
    }
    
    /**
     * 设置按钮监听器
     */
    private void setListeners() {
        // 网络操作对比
        btnWrongNetworkOp.setOnClickListener(v -> demonstrateWrongNetworkOperation());
        btnCorrectNetworkOp.setOnClickListener(v -> demonstrateCorrectNetworkOperation());
        
        // 文件操作对比
        btnWrongFileOp.setOnClickListener(v -> demonstrateWrongFileOperation());
        btnCorrectFileOp.setOnClickListener(v -> demonstrateCorrectFileOperation());
        
        // UI阻塞操作对比
        btnWrongUIBlock.setOnClickListener(v -> demonstrateWrongUIBlockOperation());
        btnCorrectUIBlock.setOnClickListener(v -> demonstrateCorrectUIBlockOperation());
        
        // 广播接收器对比
        btnWrongBroadcast.setOnClickListener(v -> simulateWrongBroadcastReceiver());
        btnCorrectBroadcast.setOnClickListener(v -> simulateCorrectBroadcastReceiver());
    }
    
    //===================== 网络操作案例 =======================
    
    /**
     * 错误的网络操作示例
     * 
     * 错误原因：在主线程中直接执行网络请求，会导致ANR
     * Android禁止在主线程进行网络操作，会抛出NetworkOnMainThreadException
     * Android 3.0 (API 11)以上版本默认开启此限制
     */
    private void demonstrateWrongNetworkOperation() {
        logMessage("[错误示例] 在主线程中执行网络请求...");
        logMessage("错误原因：阻塞主线程，且Android禁止主线程网络操作");
        
        try {
            // 模拟一个网络请求
            // 实际上Android会直接抛出NetworkOnMainThreadException异常
            // 这里用休眠来模拟，以便观察
            logMessage("正在主线程中执行网络请求...");
            
            // 模拟网络延迟
            SystemClock.sleep(5000);
            
            logMessage("网络请求完成（在真实环境中会抛出NetworkOnMainThreadException异常）");
            
        } catch (Exception e) {
            logMessage("错误：" + e.getMessage());
        }
    }
    
    /**
     * 正确的网络操作示例
     * 
     * 正确方法：使用异步任务或工作线程执行网络请求
     * 这里展示了三种常见的异步实现方式：
     * 1. AsyncTask（已弃用但面试常考）
     * 2. 线程池
     * 3. Handler+Looper工作线程
     */
    private void demonstrateCorrectNetworkOperation() {
        logMessage("[正确示例] 使用异步方式执行网络请求...");
        
        // 方法1：使用AsyncTask (虽然已弃用，但仍是面试常考点)
        logMessage("方式1：使用AsyncTask执行网络请求");
        new NetworkAsyncTask(this).execute();
        
        // 方法2：使用线程池
        logMessage("方式2：使用线程池执行网络请求");
        executorService.execute(() -> {
            logMessage("线程池中：开始模拟网络请求");
            
            // 模拟网络操作
            SystemClock.sleep(2000);
            
            // 网络操作完成后，回到主线程更新UI
            runOnUiThread(() -> logMessage("线程池完成网络请求，回到主线程更新UI"));
        });
        
        // 方法3：使用Handler工作线程
        logMessage("方式3：使用Handler工作线程执行网络请求");
        Handler handler = new Handler(Looper.getMainLooper());
        new Thread(() -> {
            logMessage("工作线程中：开始模拟网络请求");
            
            // 模拟网络操作
            SystemClock.sleep(3000);
            
            // 网络操作完成后，通过Handler回到主线程
            handler.post(() -> logMessage("Handler回调主线程更新UI"));
        }).start();
    }
    
    /**
     * 网络请求AsyncTask示例
     * 注意：AsyncTask已在Android 11 (API 30)中弃用，但仍是面试常考点
     */
    private static class NetworkAsyncTask extends AsyncTask<Void, Void, String> {
        private final WeakReference<ANRComparisonActivity> activityRef;
        
        NetworkAsyncTask(ANRComparisonActivity activity) {
            this.activityRef = new WeakReference<>(activity);
        }
        
        @Override
        protected void onPreExecute() {
            ANRComparisonActivity activity = activityRef.get();
            if (activity != null) {
                activity.logMessage("AsyncTask：准备网络请求");
            }
        }
        
        @Override
        protected String doInBackground(Void... params) {
            // 模拟网络请求
            SystemClock.sleep(1000);
            return "网络请求结果";
        }
        
        @Override
        protected void onPostExecute(String result) {
            ANRComparisonActivity activity = activityRef.get();
            if (activity != null) {
                activity.logMessage("AsyncTask：完成网络请求，结果：" + result);
            }
        }
    }
    
    //===================== 文件操作案例 =======================
    
    /**
     * 错误的文件操作示例
     * 
     * 错误原因：在主线程中执行大文件IO操作，会导致ANR
     */
    private void demonstrateWrongFileOperation() {
        logMessage("[错误示例] 在主线程中执行文件操作...");
        logMessage("错误原因：IO操作速度受设备影响很大，可能导致主线程长时间阻塞");
        
        try {
            // 创建一个临时文件
            File tempFile = File.createTempFile("anr_demo", ".txt", getCacheDir());
            
            // 写入一些数据
            logMessage("正在主线程写入大文件...");
            FileOutputStream fos = new FileOutputStream(tempFile);
            byte[] data = new byte[1024 * 1024]; // 1MB数据
            
            // 写入10MB的数据
            for (int i = 0; i < 10; i++) {
                fos.write(data);
                fos.flush();
            }
            fos.close();
            
            // 读取文件
            logMessage("正在主线程读取大文件...");
            FileInputStream fis = new FileInputStream(tempFile);
            byte[] buffer = new byte[1024];
            while (fis.read(buffer) != -1) {
                // 读取所有数据
            }
            fis.close();
            
            // 删除临时文件
            tempFile.delete();
            
            logMessage("文件操作完成，但UI在操作期间被阻塞");
            
        } catch (IOException e) {
            logMessage("文件操作出错：" + e.getMessage());
        }
    }
    
    /**
     * 正确的文件操作示例
     * 
     * 正确方法：在工作线程中执行IO操作
     */
    private void demonstrateCorrectFileOperation() {
        logMessage("[正确示例] 使用工作线程执行文件操作...");
        
        executorService.execute(() -> {
            try {
                logMessage("工作线程：开始文件操作");
                
                // 创建一个临时文件
                File tempFile = File.createTempFile("anr_demo", ".txt", getCacheDir());
                
                // 写入一些数据
                logMessage("工作线程：写入大文件");
                FileOutputStream fos = new FileOutputStream(tempFile);
                byte[] data = new byte[1024 * 1024]; // 1MB数据
                
                // 写入10MB的数据
                for (int i = 0; i < 10; i++) {
                    fos.write(data);
                    fos.flush();
                    // 更新进度
                    final int progress = (i + 1) * 10;
                    runOnUiThread(() -> logMessage("写入进度：" + progress + "%"));
                }
                fos.close();
                
                // 读取文件
                logMessage("工作线程：读取大文件");
                FileInputStream fis = new FileInputStream(tempFile);
                byte[] buffer = new byte[1024];
                while (fis.read(buffer) != -1) {
                    // 读取所有数据
                }
                fis.close();
                
                // 删除临时文件
                tempFile.delete();
                
                // 更新UI
                runOnUiThread(() -> logMessage("文件操作完成，UI保持响应"));
                
            } catch (IOException e) {
                final String errorMessage = e.getMessage();
                runOnUiThread(() -> logMessage("文件操作出错：" + errorMessage));
            }
        });
    }
    
    //===================== UI阻塞案例 =======================
    
    /**
     * 错误的UI阻塞操作示例
     * 
     * 错误原因：在主线程中执行耗时计算，导致UI无响应
     */
    private void demonstrateWrongUIBlockOperation() {
        logMessage("[错误示例] 在主线程中执行耗时计算...");
        logMessage("错误原因：主线程负责UI更新，耗时计算会导致界面无响应");
        
        // 执行一个计算密集型任务
        logMessage("开始计算斐波那契数列(n=40)...");
        long startTime = System.currentTimeMillis();
        
        long result = calculateFibonacci(40);
        
        long endTime = System.currentTimeMillis();
        logMessage("计算结果：" + result);
        logMessage("计算耗时：" + (endTime - startTime) + "毫秒");
        logMessage("注意观察：计算过程中，UI完全无响应");
    }
    
    /**
     * 正确的UI非阻塞操作示例
     * 
     * 正确方法：将耗时计算放入工作线程，保持UI响应
     */
    private void demonstrateCorrectUIBlockOperation() {
        logMessage("[正确示例] 在工作线程中执行耗时计算...");
        
        // 更新UI，显示开始计算
        logMessage("开始计算斐波那契数列(n=40)...");
        
        // 创建工作线程
        new Thread(() -> {
            long startTime = System.currentTimeMillis();
            
            // 在工作线程中执行耗时计算
            long result = calculateFibonacci(40);
            
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            
            // 计算完成，回到主线程更新UI
            runOnUiThread(() -> {
                logMessage("计算结果：" + result);
                logMessage("计算耗时：" + duration + "毫秒");
                logMessage("注意观察：计算过程中，UI保持响应");
            });
        }).start();
    }
    
    /**
     * 计算斐波那契数列的递归实现
     * 故意使用效率低的递归实现，便于制造耗时操作
     */
    private long calculateFibonacci(int n) {
        if (n <= 1) return n;
        return calculateFibonacci(n - 1) + calculateFibonacci(n - 2);
    }
    
    //===================== 广播接收器案例 =======================
    
    /**
     * 模拟错误的广播接收器实现
     * 
     * 错误原因：在广播接收器的onReceive方法中执行耗时操作
     * 广播接收器运行在主线程，onReceive方法中的耗时操作会导致ANR
     */
    private void simulateWrongBroadcastReceiver() {
        logMessage("[错误示例] 模拟广播接收器中的耗时操作...");
        logMessage("错误原因：广播接收器的onReceive方法在主线程中执行，耗时操作会导致ANR");
        
        logMessage("广播接收器收到广播");
        logMessage("开始在接收器中执行耗时操作...");
        
        // 模拟在广播接收器的onReceive方法中执行的耗时操作
        SystemClock.sleep(5000);
        
        logMessage("广播处理完成（实际会导致ANR，广播超时为10秒）");
    }
    
    /**
     * 模拟正确的广播接收器实现
     * 
     * 正确方法：
     * 1. 对于简短操作，在onReceive直接处理
     * 2. 对于耗时操作，使用goAsync()方法或启动服务来处理
     */
    private void simulateCorrectBroadcastReceiver() {
        logMessage("[正确示例] 模拟广播接收器中的正确实现...");
        
        logMessage("方式1：使用goAsync处理异步操作");
        logMessage("广播接收器收到广播，调用goAsync()获取PendingResult");
        
        // 模拟goAsync实现
        executorService.execute(() -> {
            logMessage("异步任务：开始处理耗时操作");
            
            // 模拟耗时处理
            SystemClock.sleep(5000);
            
            runOnUiThread(() -> logMessage("异步任务完成，调用pendingResult.finish()"));
        });
        
        logMessage("方式2：启动IntentService处理耗时任务");
        logMessage("广播接收器仅用于启动服务，立即返回，避免ANR");
    }
    
    /**
     * 记录日志信息到界面
     */
    private void logMessage(String message) {
        Log.d(TAG, message);
        
        // 确保在主线程更新UI
        if (Looper.myLooper() == Looper.getMainLooper()) {
            appendLogMessage(message);
        } else {
            runOnUiThread(() -> appendLogMessage(message));
        }
    }
    
    /**
     * 添加日志消息到文本框
     */
    private void appendLogMessage(String message) {
        String currentText = tvLogger.getText().toString();
        String newText = currentText + "\n" + message;
        tvLogger.setText(newText);
        
        // 滚动到底部
        svLogger.post(() -> svLogger.fullScroll(View.FOCUS_DOWN));
    }
} 